﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using CMS6Tools.Common;

namespace CMS6Tools.Performances.DataAnalytics
{
    public partial class PingdomAnalyticsForm : Form
    { 
        #region Ctor
        public PingdomAnalyticsForm()
        {
            InitializeComponent();
        }
        #endregion

        #region Form Load
        private void PingdomAnalyticsForm_Load(object sender, EventArgs e)
        {
            PingdomUrlTextBox.Text = "https://api.pingdom.com";
            UserNameTextBox.Text = "webmaster@test.com";
            PasswordTextBox.Text = "Vision3100!";
            AppKeyTextBox.Text = "sirwk18w28ck2umhdq7rsg5rgub363pr";
            ResolutionComboBox.DataSource = new  string[]
            {
                "hour",
                "day",
                "week"
            };
            ResolutionComboBox.Enabled = false;
            ResolutionComboBox.SelectedIndex = 0;

            var dateTimeNow = DateTime.Now;
            var endDate = new DateTime(dateTimeNow.Year, dateTimeNow.Month, dateTimeNow.Day, dateTimeNow.Hour, 0, 0);
            StartDateTimePicker.Value = endDate.Subtract(new TimeSpan(7, 0, 0, 0));
            EndDateTimePicker.Value = endDate; 
        }
        #endregion

        #region GetSensor Button Event
        private void GetSitesButton_Click(object sender, EventArgs e)
        {
            var pingdomApiClient = GetPingdomApiClient();
            var allChecks = pingdomApiClient.GetAllChecks(); 
            SitesCheckedListBox.Items.Clear();
            foreach (var check in allChecks.OrderBy(c => c.Name))
            {
                SitesCheckedListBox.Items.Add(check, true);
            }

            TotalLabel.Text = string.Format("Total: {0}.", allChecks.Count);
            SelectedSensorsLabel.Text = string.Format("Selected: {0}.", SitesCheckedListBox.CheckedItems.Count);
        }
        #endregion

        #region Select All
        private void SelectAllCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            for (var index = 0; index < SitesCheckedListBox.Items.Count; index++)
                SitesCheckedListBox.SetItemChecked(index, SelectAllCheckBox.Checked);
            SelectedSensorsLabel.Text = string.Format("Selected: {0}.", SitesCheckedListBox.CheckedItems.Count);
        }
        #endregion

        #region Export
        private void ExportButton_Click(object sender, EventArgs e)
        {
            var analyticsResult = new List<PingdomAnalyticsResponseTimeData>();
            var responseTimeGoal1 = 1000;
            var responseTimeGoal2 = 2000;
            var averageRemoval = string.IsNullOrEmpty(AverageRemovalTextBox.Text) ? 0 : int.Parse(AverageRemovalTextBox.Text);
            if (averageRemoval >= 50 || averageRemoval <= 0)
                averageRemoval = 0;

            var count = SitesCheckedListBox.CheckedItems.Count;
            var index = 0;
            progressBar1.Minimum = 0;
            progressBar1.Maximum = count;
            progressBar1.Value = 0;
            var originalDataList = new List<PingdomResponseTimeData>();

            var pingdomApiClient = GetPingdomApiClient();
            var allProbes = pingdomApiClient.GetProbes();
            var probesStr = allProbes.Where(c => c.CountryIso.Equals(PingdomApiClient.USCountryISO, StringComparison.InvariantCultureIgnoreCase)
                                           || c.CountryIso.Equals(PingdomApiClient.CanadaCountryISO, StringComparison.InvariantCultureIgnoreCase))
                                    .Select(c => c.ID)
                                    .Aggregate("", (seed, next) => string.Format("{0},{1}", seed, next))
                                    .Trim(',');

            foreach (var item in SitesCheckedListBox.CheckedItems)
            {
                if (index == count)
                    break;

                var site = item as PingdomCheck;
                progressBar1.Value = index + 1;
                var list = new List<PingdomSummaryPerformanceHour>();
                var response = pingdomApiClient.GetSummaryPerformance(site.ID,
                                                               probesStr,
                                                               StartDateTimePicker.Value,
                                                               EndDateTimePicker.Value,
                                                               ResolutionComboBox.SelectedValue.ToString());
                response.Name = site.Name;

                if(ResolutionComboBox.SelectedValue.ToString() =="hour")
                {
                    list = response.Hours.OrderBy(c=>c.AvgResponse).ToList();
                }
                var totalCount = list.Count();

                var analytics = new PingdomAnalyticsResponseTimeData()
                {
                    ID = site.ID,
                    SiteName = site.Name,
                    HostName = site.Hostname
                };

                if (totalCount > 0)
                {
                    var averageStart = (int)(totalCount * averageRemoval / 100.0);
                    var averageCount = (int)(totalCount * (100 - 2 * averageRemoval) / 100.0);

                    analytics.Average = list.Skip(averageStart).Take(averageCount).Sum(c => c.AvgResponse) / averageCount;

                    analytics.Percentage20 = GetPecentageData(list, 0.2f).AvgResponse;
                    analytics.Percentage50 = GetPecentageData(list, 0.5f).AvgResponse;
                    analytics.Percentage90 = GetPecentageData(list, 0.9f).AvgResponse;
                    analytics.Percentage95 = GetPecentageData(list, 0.95f).AvgResponse;
                    analytics.Min = list.Min(c => c.AvgResponse);
                    analytics.Max = list.Max(c => c.AvgResponse);
                    analytics.TotalLessThanGoal1000 = list.Count(c => c.AvgResponse <= responseTimeGoal1);
                    analytics.TotalLessThanGoal2000 = list.Count(c => c.AvgResponse <= responseTimeGoal2);
                    analytics.Total = totalCount;
                }
                analyticsResult.Add(analytics);

                originalDataList.AddRange(list.Select(c => new PingdomResponseTimeData
                {
                    CheckID = site.ID,
                    StartTime = c.StartTime,
                    AvgResponse = c.AvgResponse
                }));
                index++;
            }

            WriteResponseTimeAnalyticsIntoCsv(originalDataList, analyticsResult.ToArray());

            MessageBox.Show("Exported Success."); 
        }
        #endregion
        
        #region Helper Methods
        PingdomApiClient GetPingdomApiClient()
        {
            return new PingdomApiClient (PingdomUrlTextBox.Text,UserNameTextBox.Text,PasswordTextBox.Text, AppKeyTextBox.Text);
        }
         
        T GetPecentageData<T>(List<T> orderedDataList, float pecentage)
        {
            if (!orderedDataList.Any())
                return default(T);
            if (pecentage >= 1)
                pecentage = 1;
            var index = (int)(pecentage * orderedDataList.Count);
            if (index == orderedDataList.Count)
                index = orderedDataList.Count - 1;
            return orderedDataList[index];
        }

        void WriteResponseTimeAnalyticsIntoCsv(IEnumerable<PingdomResponseTimeData> oringalData, params PingdomAnalyticsResponseTimeData[] dataList)
        {
            if (dataList.Any())
            {
                var tempFileName = string.Format("Pingdom_ResponseAnalytics_{0}.csv", DateTime.Now.ToString("yyyyMMddHHmmss"));
                var exeDirectory = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
                var tempFilePath = System.IO.Path.Combine(exeDirectory, tempFileName);

                var carriageReturn = "\r\n";
                var commaStr = ",";

                var responseTimeGoal1 = 1000;
                var responseTimeGoal2 = 2000;
                using (var streamWriter = new StreamWriter(tempFilePath, false))
                {
                    var resultBuilder = new StringBuilder();
                    resultBuilder.AppendFormat("Id,Site Name,Host Name,Average,Min,Max,20%,50%,90%,95%,Total Tests,<{0} msc %,<{1} msc %", responseTimeGoal1, responseTimeGoal2);
                    foreach (var data in dataList)
                    {
                        resultBuilder.Append(carriageReturn);
                        resultBuilder.Append(data.ID);
                        resultBuilder.AppendFormat("{0}\"{1}\"", commaStr, data.SiteName);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.HostName);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Average);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Min);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Max);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Percentage20);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Percentage50);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Percentage90);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Percentage95);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, data.Total);
                        //resultBuilder.AppendFormat("{0}{1}", commaStr, data.TotalLessThanGoal);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, (100.0f * data.TotalLessThanGoal1000) / data.Total);
                        resultBuilder.AppendFormat("{0}{1}", commaStr, (100.0f * data.TotalLessThanGoal2000) / data.Total);
                    }
                    resultBuilder.Append(carriageReturn);
                    streamWriter.Write(resultBuilder.ToString());
                }

                using (var streamWriter = new StreamWriter(tempFilePath + ".xml", false))
                {
                    var xmlSerializer = new XmlSerializer(typeof(List<PingdomResponseTimeData>));
                    xmlSerializer.Serialize(streamWriter, oringalData.OrderBy(c=>c.CheckID).OrderBy(c=>c.StartTime).ToList());
                }
            }
        }
        
        #endregion

        private void SitesCheckedListBox_SelectedValueChanged(object sender, EventArgs e)
        {
            SelectedSensorsLabel.Text = string.Format("Selected: {0}.", SitesCheckedListBox.CheckedItems.Count);
        }
    }
}
